﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.IO;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Drawing.Imaging;

namespace CSMF.ValidateCode.lib
{
    /// <summary>
    /// ClassName:DrawValidateImg
    /// Auther:Hyey.wl
    /// Time:2010-04-30
    /// Other:
    /// DrawValidateImg 的摘要说明。
    /// </summary>
    public class DrawValidateImg
    {
        /// <summary>
        /// 无参构造
        /// Initializes a new instance of the <see cref="DrawValidateImg"/> class.
        /// </summary>
        public DrawValidateImg()
        {
            //
            // TODO: 在此处添加构造函数逻辑
            //
        }


        /// <summary>
        /// 带有生成字符个数的构造
        /// Initializes a new instance of the <see cref="DrawValidateImg"/> class.
        /// </summary>
        /// <param name="charNum">The char num.验证码中包含随机字符的个数</param>
        public DrawValidateImg(int charNum)
        {
            this.CharNum = charNum;
        }


        /// <summary>
        /// 带有验证码图片宽度和高度的构造
        /// Initializes a new instance of the <see cref="DrawValidateImg"/> class.
        /// </summary>
        /// <param name="width">The width.验证码图片宽度</param>
        /// <param name="height">The height.验证码图片高度</param>
        public DrawValidateImg(int width, int height)
        {
            this.width = width;
            this.height = height;
        }


        /// <summary>
        /// 带有生成字符个数，验证码图片宽度和高度的构造
        /// Initializes a new instance of the <see cref="DrawValidateImg"/> class.
        /// </summary>
        /// <param name="charNum">The char num.验证码中包含随机字符的个数</param>
        /// <param name="width">The width.验证码图片宽度</param>
        /// <param name="height">The height.验证码图片高度</param>
        public DrawValidateImg(int charNum, int width, int height)
        {
            this.CharNum = charNum;
            this.width = width;
            this.height = height;
        }


        /// <summary>
        /// 验证码中字符个数
        /// </summary>
        int charNum = 5; //默认字符个数为5

        /// <summary>
        /// 字数
        /// Gets or sets the char num.
        /// </summary>
        /// <value>The char num.</value>
        public int CharNum
        {
            get { return charNum; }
            set { charNum = value; }
        }
        /// <summary>
        /// 字号
        /// </summary>
        int fontSize = 20;

        /// <summary>
        /// 字号
        /// Gets the size of the font.
        /// </summary>
        /// <value>The size of the font.</value>
        public int FontSize
        {
            get { return fontSize; }
        }
        /// <summary>
        /// 图片宽度
        /// </summary>
        int width = 200;

        /// <summary>
        /// Gets the width.
        /// </summary>
        /// <value>The width.</value>
        public int Width
        {
            get { return width; }
        }

        /// <summary>
        /// 图片高度
        /// </summary>
        int height = 50;

        /// <summary>
        /// Gets or sets the height.
        /// </summary>
        /// <value>The height.</value>
        public int Height
        {
            get { return height; }
            set { height = value; }
        }

        /// <summary>
        /// 随机生成的字符串
        /// </summary>
        string validStr = "";

        /// <summary>
        /// Gets or sets the valid STR.
        /// 随机生成的字符串
        /// </summary>
        /// <value>The valid STR.</value>
        public string ValidStr
        {
            get { return validStr; }
            set { validStr = value; }
        }

        /// <summary>
        /// 产生指定个数的随机字符串，默认字符个数为5
        /// </summary>
        void GetValidateCode()
        {
            Random rd = new Random(); //创建随机数对象            

            //产生由 charNum 个字母或数字组成的一个字符串
            string str = "ABCDEFGHJKLMNPQRSTUVWYZ23456789";//共31个字符，除 l,o,x,I,O,X,1,0 的所有数字和大写字母

            for (int i = 0; i < charNum; i++)
            {
                validStr = validStr + str[rd.Next(30)];//返回0到54
            }

        }

        /// <summary>
        /// 由随机字符串，随即颜色背景，和随机线条产生的Image
        /// 返回 MemoryStream
        /// </summary>
        /// <returns>MemoryStream</returns>
        public MemoryStream GetImgWithValidateCode()
        {
            //产生随机字符串
            GetValidateCode();

            //声明一个位图对象
            Bitmap bitMap = null;
            //声明一个绘图画面
            Graphics gph = null;
            //创建内存流
            using (MemoryStream memStream = new MemoryStream())
            {

                Random random = new Random();

                //由给定的需要生成字符串中字符个数 CharNum， 图片宽度 Width 和高度 Height 确定字号 FontSize，
                //确保不因字号过大而不能全部显示在图片上
                int fontWidth = (int)Math.Round(width / (charNum + 2) / 1.3);
                int fontHeight = (int)Math.Round(height / 1.5);
                //字号取二者中小者，以确保所有字符能够显示，并且字符的下半部分也能显示
                fontSize = fontWidth <= fontHeight ? fontWidth : fontHeight;

                //创建位图对象
                bitMap = new Bitmap(width + FontSize, height);

                //根据上面创建的位图对象创建绘图图面
                gph = Graphics.FromImage(bitMap);

                //设定验证码图片背景色
                gph.Clear(GetControllableColor(200));
                //gph.Clear(Color.White);

                //产生随机干扰线条
                //              for (int i = 0; i < 10; i++)
                //              {
                //                  Pen backPen = new Pen(GetControllableColor(100), 2);
                //                  //线条起点
                //                  int x = random.Next(width);
                //                  int y = random.Next(height);
                //                  //线条终点
                //                  int x2 = random.Next(width);
                //                  int y2 = random.Next(height);
                //                  //划线
                //                  gph.DrawLine(backPen, x, y, x2, y2);
                //              }

                //定义一个含10种字体的数组
                String[] fontFamily ={ "Arial", "Verdana", "Comic Sans MS", "Impact", "Haettenschweiler", 
                                         "Lucida Sans Unicode", "Garamond", "Courier New", "Book Antiqua", "Arial Narrow" };
                //              SolidBrush sb = new SolidBrush(GetControllableColor(0));

                PointF Cpoint1 = new PointF(5, 5);
                Random rnd1 = new Random();
                int x1 = 0, y1 = 0;
                //通过循环,绘制每个字符,
                for (int i = 0; i < validStr.Length; i++)
                {
                    //随机字符位置   
                    x1 = rnd1.Next(10) + 40 * i;
                    y1 = rnd1.Next(bitMap.Height / 4);
                    Cpoint1 = new PointF(x1, y1);

                    //随机字符颜色,应根据背景作适当调整以免显示模糊不清
                    SolidBrush sb = new SolidBrush(Color.FromArgb(rnd1.Next(100), rnd1.Next(100), rnd1.Next(100)));


                    //Font textFont = new Font(fontFamily[random.Next(10)], fontSize, FontStyle.Bold);//字体随机,字号大小30,加粗 
                    Font textFont = new Font("Arial", 35, FontStyle.Bold);//字体随机,字号大小30,加粗 

                    //随机倾斜字符  
                    gph.TranslateTransform(10, 0);
                    Matrix transform = gph.Transform;
                    transform.Shear(Convert.ToSingle(rnd1.NextDouble() - 0.5), 0.001f);
                    gph.Transform = transform;
                    //每次循环绘制一个字符,设置字体格式,画笔颜色,字符相对画布的X坐标,字符相对画布的Y坐标
                    //int space = (int)Math.Round((double)((width - fontSize * (CharNum + 2)) / CharNum));
                    //纵坐标
                    int y = (int)Math.Round((double)((height - fontSize) / 3));
                    //                  gph.DrawString(validStr.Substring(i, 1), textFont, sb, fontSize + i * (fontSize + space), y);
                    gph.DrawString(validStr.Substring(i, 1), textFont, sb, Cpoint1);
                    gph.ResetTransform();
                }
                //扭曲图片
                //bitMap=TwistImage(bitMap, true, random.Next(3,5),random.Next(3));


                //画图片的前景噪音点
                //              for (int i = 0; i < 10; i++)
                //              {
                //                  int x = random.Next(bitMap.Width);
                //                  int y = random.Next(bitMap.Height);
                //                  bitMap.SetPixel(x, y, Color.White);
                //              }

                //画图片的边框线
                gph.DrawRectangle(new Pen(Color.Black, 2), 0, 0, bitMap.Width - 1, bitMap.Height - 1);


                try
                {

                    bitMap.Save(memStream, ImageFormat.Gif);

                }
                catch (Exception ex)
                {
                    // TODO; a
                    //System.Windows.Forms.MessageBox.Show(ex.Message);
                }

                bitMap.Dispose();

                //              Image img = Image.FromStream(memStream);
                //              gph.DrawImage(img, 50, 20, width, 10);

                //gph.Dispose();
                //return img;
                return memStream;
            }
        }
        /// <summary>
        /// 产生一种 R,G,B 均大于 colorBase 随机颜色，以确保颜色不会过深
        /// </summary>
        /// <param name="colorBase">The color base.</param>
        /// <returns>背景色</returns>
        Color GetControllableColor(int colorBase)
        {
            Color color = Color.Black;
            if (colorBase > 200)
            {
                //System.Windows.Forms.MessageBox.Show("可控制颜色参数大于200，颜色默认位黑色");
            }
            Random random = new Random();
            //确保 R,G,B 均大于 colorBase，这样才能保证背景色较浅
            color = Color.FromArgb(random.Next(56) + colorBase, random.Next(56) + colorBase, random.Next(56) + colorBase);
            return color;
        }

        /// <summary>
        /// 扭曲图片
        /// </summary>
        /// <param name="srcBmp">The SRC BMP.</param>
        /// <param name="bXDir">if set to <c>true</c> [b X dir].</param>
        /// <param name="dMultValue">The d mult value.</param>
        /// <param name="dPhase">The d phase.</param>
        /// <returns></returns>
        Bitmap TwistImage(Bitmap srcBmp, bool bXDir, double dMultValue, double dPhase)
        {
            int leftMargin = 0;
            int rightMargin = 0;
            int topMargin = 0;
            int bottomMargin = 0;
            //float PI = 3.14159265358979f;
            float PI2 = 6.28318530717959f;
            Bitmap destBmp = new Bitmap(srcBmp.Width, srcBmp.Height);
            double dBaseAxisLen = bXDir ? Convert.ToDouble(destBmp.Height) : Convert.ToDouble(destBmp.Width);
            for (int i = 0; i < destBmp.Width; i++)
            {
                for (int j = 0; j < destBmp.Height; j++)
                {
                    double dx = 0;
                    dx = bXDir ? PI2 * Convert.ToDouble(j) / dBaseAxisLen : PI2 * Convert.ToDouble(i) / dBaseAxisLen;
                    dx += dPhase;
                    double dy = Math.Sin(dx);

                    //取得当前点的颜色        
                    int nOldX = 0;
                    int nOldY = 0;
                    nOldX = bXDir ? i + Convert.ToInt32(dy * dMultValue) : i;
                    nOldY = bXDir ? j : j + Convert.ToInt32(dy * dMultValue);
                    System.Drawing.Color color = srcBmp.GetPixel(i, j);
                    if (nOldX >= leftMargin && nOldX < destBmp.Width - rightMargin && nOldY >= bottomMargin && nOldY < destBmp.Height - topMargin)
                    {
                        destBmp.SetPixel(nOldX, nOldY, color);
                    }
                }
            }
            return destBmp;
        }

        /// <summary>
        /// 判断验证码是否正确
        /// </summary>
        /// <param name="inputValCode">待判断的验证码</param>
        /// <returns>正确返回 true,错误返回 false</returns>
        public bool IsRight(string inputValCode)
        {

            if (validStr.ToUpper().Equals(inputValCode.ToUpper()))//无论输入大小写都转换为大些判断
            {
                return true;
            }
            else
            {
                return false;
            }
        }
    }
}